﻿using Nes.Core.Mappers;
using Nes.Core.PPUS;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace Nes.Core.Buss
{
    internal class PPUBus : IBus
    {
        private readonly ICartridge cartridge;
        /// <summary>
        /// 偏移量 2000
        /// 2kb 存放 nametable + attribute
        /// </summary>
        private readonly Ram vram_NameTable_AttributeTable = new (0x0800, 0x2000);
        /// <summary>
        /// 背景 0x3F00
        /// 16字节
        /// </summary>
        private readonly Ram vram_BackgrandPalette = new (0x10, 0x3F00);
        /// <summary>
        /// 精灵 0x3F10
        /// 16字节
        /// </summary>
        private readonly Ram vram_SpritePalette = new (0x10, 0x3F10);


        public PPUBus(ICartridge cartridge)
        {
            this.cartridge = cartridge;
        }

        public Byte ReadByte(int address)
        {
            // 只有 14 bit可用
            address &= 0b0011_1111_1111_1111;
            if (address < 0x2000)
            {
                return this.cartridge.Mapper.Read(address);
            }
            else if (address < 0x3000)
            {
                // 0X2000 - 0X23BF
                // 0X23C0 - 0X23FF
                // 0X2400 - 0X27FF
                // 0X2800 - 0X2BFF
                // 0X2C00 - 0X2FFF
                return this.vram_NameTable_AttributeTable.Read(ParseMirrorAddress(address));
            }
            else if (address < 0x3F00)
            {
                // Mirrors $2000 -$2EFF
                // 可以忽略 2kb
                return ReadByte(address - 0x1000);
            }
            //else if(address < 0x3FFF)
            else
            {
                // $3F00 - $ 3FFF
                // 0011_1111_0001_1111
                address &= 0x3F1F;
                // $3F00 - $ 3F1F
                // 32字节
                // $3F00 - $ 3F0F
                // 背景调色盘
                // $3F10 - $ 3F1F
                // 精灵调色盘
                if (address < 0x3F10)
                {
                    return vram_BackgrandPalette.Read(address);
                }
                // 0x?4 0x?8 0x?c 
                else if ((address & 0b11) == 0)
                {
                    return vram_BackgrandPalette.Read(address - 0x10);
                }
                else
                {
                    return vram_SpritePalette.Read(address);
                }
            }
        }

        public UInt16 ReadWord(Int32 address)
        {
            return (UInt16)(ReadByte(address) | ReadByte(address + 1) << 8);
        }

        public void WriteByte(Int32 address, Byte data)
        {
            // 只有 14 bit可用
            address &= 0b0011_1111_1111_1111;
            if (address < 0x2000)
            {   // 0X0000 - 0X1FFF 
                // Pattern Table 0 4KB
                // Pattern Table 1 4KB
                cartridge.Mapper.Write(address, data);
            }
            else if (address < 0x3000)
            {
                // 四个NameTable AttributeTable
                // 0X2000 - 0X23BF
                // 0X23C0 - 0X23FF
                // 0X2400 - 0X27FF
                // 0X2800 - 0X2BFF
                // 0X2C00 - 0X2FFF
                vram_NameTable_AttributeTable.Write(ParseMirrorAddress(address), data);
            }
            else if (address < 0x3F00)
            {
                // PPU未使用
                WriteByte(address - 0x1000, data);
            }
            else
            {
                // 0x3F20 - 0x3FFF 
                address &= 0x3F1F;
                if (address < 0x3F10)
                {
                    // 0x3F00 - 0x3F1F 
                    // Palette Index (调色盘)
                    vram_BackgrandPalette.Write(address, data);
                }
                else if ((address & 0b11) == 0)
                {
                    vram_BackgrandPalette.Write(address - 0x10, data);
                }
                else
                {
                    vram_SpritePalette.Write(address, data);
                }
            }
        }

        public void WriteWord(Int32 address, UInt16 data)
        {
            WriteByte(address, (Byte)(data & 0xFF));
            WriteByte(address + 1, (Byte)((data >> 8) & 0xFF));
        }

        /// <summary>
        /// 通过卡带的镜像方式重新映射 nametables
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        /// <exception cref="NotSupportedException"></exception>
        private Int32 ParseMirrorAddress(int address)
        {
            return cartridge.HeaderInfo.Mirror switch
            {
                //
                Mirror.HORIZONTAL => (address & 0x23FF) | ((address & 0x0800) > 0 ? 0x0400 : 0),
                // 0b00100111_11111111
                Mirror.VERTICAL => address & 0x27FF,
                Mirror.FOUR_SCREEN => address,
                // 待验证
                Mirror.SINGLE_SCREEN_LOWER_BANK => address & 0x23FF,
                Mirror.SINGLE_SCREEN_UPPER_BANK => address & 0x23FF + 0x0400,
                _ => throw new NotSupportedException("未实现"),
            };
        }
    }
}
